/*
    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Charles Mac Donald

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include "shared.h"

static int use_cpu68k_type;

uint8 cart_rom[0x400000] CACHEALIGN;   /* Cartridge ROM */
uint8 work_ram[0x10000] CACHEALIGN;    /* 68K work RAM */
uint8 zram[0x2000] CACHEALIGN;         /* Z80 work RAM */
uint8 zbusreq;              /* /BUSREQ from Z80 */
uint8 zreset;               /* /RESET to Z80 */
uint8 zbusack;              /* /BUSACK to Z80 */
uint8 zirq;                 /* /IRQ to Z80 */
uint32 zbank;               /* Address of Z80 bank window */
uint8 gen_running;

/*--------------------------------------------------------------------------*/
/* Init, reset, shutdown functions                                          */
/*--------------------------------------------------------------------------*/

void gen_init(int cpu68k_type)
{
  use_cpu68k_type = cpu68k_type;

  sound_init();
  snd.sample_rate = 0;
  snd.enabled = 0;
  snd.buffer_size = 0;

  M68K_Init(use_cpu68k_type);
  // gperror("PC:%08X\tSP:%08X\n", M68K_GetPC(use_cpu68k_type), M68K_GetSP());
  gen_running = 1;
}

void gen_reset(void)
{
    /* Clear RAM */
    memset(work_ram, 0, sizeof(work_ram));
    memset(zram, 0, sizeof(zram));

    gen_running = 1;
    zreset  = 0;    /* Z80 is reset */
    zbusreq = 0;    /* Z80 has control of the Z bus */
    zbusack = 1;    /* Z80 is busy using the Z bus */
    zbank   = 0;    /* Assume default bank is 000000-007FFF */
    zirq    = 0;    /* No interrupts occuring */

    io_reset();

    /* Reset the 68000 emulator */
    M68K_Reset(use_cpu68k_type);
    // gperror("PC:%08X\tSP:%08X\n", M68K_GetPC(use_cpu68k_type), M68K_GetSP());
#ifdef CPUZ80_USE_CZ80
    // CZ80
    Cz80_Init(&CZ80);
    
    Cz80_Set_Fetch(&CZ80, 0x0000, 0x1FFF, (u32)zram);
    Cz80_Set_Fetch(&CZ80, 0x2000, 0x3FFF, (u32)zram);

    Cz80_Set_ReadB(&CZ80, cpu_readmem16);
    Cz80_Set_WriteB(&CZ80, cpu_writemem16);
    Cz80_Set_INPort(&CZ80, cpu_readport16);
    Cz80_Set_OUTPort(&CZ80, cpu_writeport16);
    Cz80_Set_IRQ_Callback(&CZ80, z80_irq_callback);
    Cz80_Reset(&CZ80);
#else
    z80_reset(0);
    z80_set_irq_callback(z80_irq_callback);
#endif

    /* Reset SRAM handler */
    sram_reset();
}

void gen_shutdown(void)
{
/*    int i;

    // gperror("\n");
    // gperror("\nPC:%08X\tSP:%08X\tSR:%04X\n", M68K_GetPC(use_cpu68k_type), M68K_GetSP(), M68K_GetSR(use_cpu68k_type));
    for(i=0;i<8;i++)
    {
        // gperror("D%d:%08X\tA%d:%08X\n",
            i, M68K_GetDReg(use_cpu68k_type, i),
            i, M68K_GetAReg(use_cpu68k_type, i));
    }

    // gperror("\n");
    // gperror("PC:%04X\tSP:%04X\n", z80_get_reg(Z80_PC), z80_get_reg(Z80_SP));
    // gperror("AF:%04X\tAF:%04X\n", z80_get_reg(Z80_AF), z80_get_reg(Z80_AF2));
    // gperror("BC:%04X\tBC:%04X\n", z80_get_reg(Z80_BC), z80_get_reg(Z80_BC2));
    // gperror("DE:%04X\tDE:%04X\n", z80_get_reg(Z80_DE), z80_get_reg(Z80_DE2));
    // gperror("HL:%04X\tHL:%04X\n", z80_get_reg(Z80_HL), z80_get_reg(Z80_HL2));
    // gperror("IX:%04X\tIY:%04X\n", z80_get_reg(Z80_IX), z80_get_reg(Z80_IY));
    // gperror("\n");*/
}

/*--------------------------------------------------------------------------*/
/* Bus controller chip functions                                            */
/*--------------------------------------------------------------------------*/

int gen_busack_r(void)
{
    return (zbusack & 1);
}

void gen_busreq_w(int state)
{
    zbusreq = (state & 1);
    zbusack = 1 ^ (zbusreq & zreset);

    if(zbusreq == 0 && zreset == 1)
    {
#ifdef CPUZ80_USE_CZ80
        Cz80_Exec(&CZ80, 32);
#else
        z80_execute(32);
#endif
    }
}

void gen_reset_w(int state)
{
    zreset = (state & 1);
    zbusack = 1 ^ (zbusreq & zreset);

    if(zreset == 0)
    {
        if(snd.enabled)
        {
            YM2612ResetChip(0);
        }

#ifdef CPUZ80_USE_CZ80
        Cz80_Reset(&CZ80);
#else
        z80_reset(0);
        z80_set_irq_callback(z80_irq_callback);
#endif
    }
}


void gen_bank_w(int state)
{
    zbank = ((zbank >> 1) | ((state & 1) << 23)) & 0xFF8000;
}



int z80_irq_callback(int param)
{
    zirq = 0;
#ifdef CPUZ80_USE_CZ80
    Cz80_Clear_IRQ(&CZ80);
#else
    z80_set_irq_line(0, CLEAR_LINE);
#endif
    return 0xFF;
}

s32 FASTCALL m68k_int_ack_callback(s32 int_level)
{
    switch(int_level)
    {
        case 4:
            hint_pending = 0;
            break;

        case 6:
            status &= ~0x0080;
            vint_pending = 0;
            break;
    }

    return CPU68K_INT_ACK_AUTOVECTOR;
}

